#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <assert.h>
#include <stack>

#include "../include/LR.h"
#include "../include/Grammar.h"
#include "../include/Token.h"

int main() {
    std::string grammar_path = "../../demo/CFG.txt";
//    std::string grammar_path = "../../demo/test.txt";
//    std::string grammar_path = "../../demo/part.txt";
    std::ifstream grammar_file(grammar_path);

    if (!grammar_file.is_open()) {
        std::cerr << "[*] failed to open grammar file\n";
        return 0;
    }
    auto read_grammar = [&]() {
        std::string line;
        std::vector<std::string> ret;
        while (std::getline(grammar_file, line)) {
            line += " ";
            ret.push_back(line);
        }
        return ret;
    };
    Grammar grammar;

    assert(0 == grammar.Scan_CFG_Grammer(read_grammar()));
    grammar.EliminateLeftRecursion();
    grammar.ExtendGrammar();
    grammar.get_First();
    LR lr = LR(grammar);
    lr.build_LR_table();
    lr.build_GOTO_ACTION_Table();
    lr.print_Action();
    lr.print_GOTO();
    for(auto & a : lr.LR_table) {
        std::cout << "state " << a->state << std::endl;
        for(auto & c : a->next_state) {
            std::cout << c.first << " -> " << c.second << std::endl;
        }
        for(auto & b : a->action) {
            std::cout << b.left << " -> ";
            for(auto & c : b.right) {
                for(auto & d : c.right) {
                    std::cout << d->name << " ";
                }
                std::cout << " | ";
                for (auto &d : c.FSS) {
                    std::cout << d->name << " ";
                }
                std::cout<<std::endl;
            }
            std::cout << std::endl;
        }
    }

    std::string token_path = "../../demo/token.txt";
    std::ifstream token_file(token_path);
    if (!token_file.is_open()) {
        std::cerr << "[*] failed to open token file\n";
        return 0;
    }
    std::vector<Token> tokens;
    int token_n;
    token_file >> token_n;
    while(token_n--) {
        int line_n;
        std::string type, value;
        token_file >> type >> line_n >> value;
        TokenType token_type;
        if ("KEYWORD" == type) {
            token_type = KEYWORD;
        } else if ("IDENTIFIER" == type) {
            token_type = IDENTIFIER;
            value = "IDENTIFIER";
        } else if ("OPERATOR" == type) {
            token_type = OPERATOR;
        } else if ("ERROR" == type) {
            token_type = ERROR;
        } else if ("SEGMENT" == type) {
            token_type = SEGMENT;
        } else if ("LITERALS" == type) {
            token_type = LITERALS;
            value = "LITERALS";
        } else if ("OTHERS" == type) {
            token_type = OTHERS;
        }
        tokens.push_back(Token(token_type, line_n, value));
    }
    token_file.close();

    bool res = lr.accept(tokens);
    if (res) {
        std::cout << "accept" << std::endl;
    } else {
        std::cout << "reject" << std::endl;
    }


    return 0;
}
